/*
 * OLED.C
 * 功能：OLED屏 驱动
 */

#include "I2C.h"
#include "OLED.h"
#include "math.h"
#include "string.h"
#include "OLED_Font.h"

/* IIC_SCL 引脚定义 */
#define OLED_SCL_PORT_RCC		__HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_SCL_PORT			GPIOB
#define OLED_SCL_PIN			GPIO_PIN_10

/* IIC_SDA 引脚定义 */
#define OLED_SDA_PORT_RCC		__HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_SDA_PORT			GPIOB
#define OLED_SDA_PIN			GPIO_PIN_11

/* IO操作 */
#define OLED_SCL(x)		HAL_GPIO_WritePin(OLED_SCL_PORT, OLED_SCL_PIN, x==0 ? GPIO_PIN_RESET : GPIO_PIN_SET);
#define OLED_SDA(x)		HAL_GPIO_WritePin(OLED_SDA_PORT, OLED_SDA_PIN, x==0 ? GPIO_PIN_RESET : GPIO_PIN_SET);

/*******************************************************************************
* 功  能: OLED写命令
* 参  数: Byte：要写入的命令
* 返回值: 无
*******************************************************************************/
void OLED_WriteCommand(uint8_t Byte)	//0X00
{
	HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x00, 1, &Byte, 1, 0xFF);	//I2C发送数据
}

/*******************************************************************************
* 功  能: OLED写数据
* 参  数: Byte：要写入的数据
*******************************************************************************/
void OLED_WriteData(uint8_t Byte)//0X40
{
	HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x40, 1 , &Byte, 1, 0xFF);	//I2C发送数据
}

/*******************************************************************************
* 功  能: OLED设置光标位置
* 参  数：Y：以左上角为原点，向下方向的坐标，范围：0~7
* 参  数：X：以左上角为原点，向右方向的坐标，范围：0~127
*******************************************************************************/
void OLED_SetCursor(uint8_t Y , uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

/*******************************************************************************
* 功  能: OLED清屏
* 参  数：无
*******************************************************************************/
void OLED_Clear(void)
{   
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/*******************************************************************************
* 功  能: OLED设置光标位置
* 参  数：Line：行位置，范围1~4
* 参  数：Column：列位置，范围1~16
* 参  数：Char：要显示的一个字符，ASCII可见字符
*******************************************************************************/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/*******************************************************************************
* 功  能: OLED显示字符串
* 参  数：Line：行位置，范围1~4
* 参  数：Column：列位置，范围1~16
* 参  数：Char：要显示的一个字符，ASCII可见字符
*******************************************************************************/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/*******************************************************************************
* 功  能: OLED显示数字（十进制，正数）
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：Number：要显示的数字，范围：0~4294967295
* 参  数：Length：要显示数字的长度，范围：1~10
*******************************************************************************/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/*******************************************************************************
* 功  能: OLED显示数字（十进制，带符号数）
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：Number：要显示的数字，范围：-2147483648~2147483647
* 参  数：Length：要显示数字的长度，范围：1~10
*******************************************************************************/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/*******************************************************************************
* 功  能: OLED显示数字（十六进制，正数）
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：Number：要显示的数字，范围：0~0xFFFFFFFF
* 参  数：Length：要显示数字的长度，范围：1~8
*******************************************************************************/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/*******************************************************************************
* 功  能: OLED显示数字（二进制，正数）
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：Number：要显示的数字，范围：0~1111 1111 1111 1111
* 参  数：Length：要显示数字的长度，范围：1~16
*******************************************************************************/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/*******************************************************************************
* 功  能: OLED初始化
* 参  数：无
*******************************************************************************/
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//上电延时
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_WriteCommand(0xAE);
	OLED_WriteCommand(0x00);
	OLED_WriteCommand(0x10);
	OLED_WriteCommand(0x00);
	OLED_WriteCommand(0xB0);

	OLED_WriteCommand(0x81);
	OLED_WriteCommand(0xff);
	OLED_WriteCommand(0xA1);
	OLED_WriteCommand(0xA6);
	OLED_WriteCommand(0xA8);
	
	OLED_WriteCommand(0x1F);
	OLED_WriteCommand(0xC8);
	OLED_WriteCommand(0xD3);
	OLED_WriteCommand(0x00);
	OLED_WriteCommand(0xD5);
	
	OLED_WriteCommand(0x80);
	OLED_WriteCommand(0xD9);
	OLED_WriteCommand(0x1f);
	OLED_WriteCommand(0xDA);
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0xdb);
	OLED_WriteCommand(0x40);
	OLED_WriteCommand(0x8d);
	OLED_WriteCommand(0x14);
	OLED_Clear();
	OLED_WriteCommand(0xAF);
}

/*******************************************************************************
* 功  能: 显示中文字符
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：Char：要显示的字符，用数字代替（见字库）
*******************************************************************************/
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(OLED_ZW[Char].Msk[i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(OLED_ZW[Char].Msk[i + 16]);		//显示下半部分内容
	}
}

/*******************************************************************************
* 功  能: 显示字符串（中英文）
* 参  数：Line：行位置，范围1~4
* 参  数：Column：起始列位置，范围：1~16
* 参  数：*s：要显示的字符串
*******************************************************************************/
void OLED_Print(uint8_t x, uint8_t y, char *s)
{
	unsigned char i,k,length;
	unsigned long Index = 0;
	unsigned long shuzhi=0;
	length = strlen(s);	//取字符串总长

	for(k=0; k<length; k++)
	{
		if(*(s+k) <= 127)
		{
			/* 小于128是ASCII符号 */
			OLED_ShowChar(x,y,*(s+k));
			y += 1;
		}
		else if(*(s+k) > 127)
		{
			/* 大于127，为汉字，前后两个组成汉字内码 */
			Index = (*(s+k) << 16) | (*(s+k+1)<<8)|(*(s+k+2));		//取汉字的内码
			for(i=0;i<sizeof(OLED_ZW)/35;i+=1)
			{
				/* 查数组 */
				shuzhi =(*(OLED_ZW[i].Index) << 16) | (*(OLED_ZW[i].Index+1)<<8)|(*(OLED_ZW[i].Index+2));
				if(Index == shuzhi)
				{
					/* 查询到这个字 */
					OLED_ShowChinese(x,y,i);
					k += 1;	//汉字占2Byte,跳过一个
				}
			}
			y=y+2;
		}
	}
}

/*******************************************************************************
* 功  能: 显示图片
* 参  数: x0(X轴起点)，y0(Y轴起点)，x1(X轴终点)，y1(Y轴终点)，PI[](要显示的图片)
*******************************************************************************/
void OLED_ShowBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char PI[])
{  
 unsigned int j=0;
 unsigned char x,y;

 for(y=y0; y<y1+1; y++)
 {
  OLED_SetCursor(y,x0);  //第一个设置y,第二个设置x		设置光标位置左上角(0,0) 往下0-7 ， 往右0-127
    for(x=x0; x<x1+1; x++)
     {      
      OLED_WriteData(PI[j++]);       //写数据
     }
 }
} 

